UPDATE 1/14/2023, v1.1:
This update couldn’t have happened without @thisismypassword’s contributions to the community. I recently began overhauling my build pipeline for future projects, and one of the first features I added was Shrinko8. Since Downstream Dream is my only project to use the full build pipeline, I used it for testing output from the new minifier, which led to some token golfing. Thanks to this tip, also by @thisismypassword, I was able to free up about 100 tokens! Changes include:
- Midboss section contains more action and a couple new sprites/sfx










Hi everyone,
My new project uses massive tables of graphics metadata, so I've written a new table serializer inspired by this pull request on @BenWiley4000's pico8-table-string to get the job done. Hopefully someone else finds this useful, too!
It uses less characters to store your table as a string than pico8-table-string does (to take up less character / compressed space), but at the cost of 14 more tokens to deserialize, and possibly with less reliability. (It will break if the table contains a string a certain character sequence, see below.) You should also run the output through something like Zep's escape_binary_string before saving to code.
Supported:
- string/number/boolean values
- key/value pairs
- consecutive indexed values starting from 1
Not supported:
- 0-indexed values
- non-consecutive indexed values

I don't feel like I have the greatest grasp on Lua metatables/metamethods, but I came across some unexpected behavior this week and was wondering if this is a bug. Example cart attached.
I'm setting up a "class" like so:
class = {} class.__index = class function class:new(instance) local instance = instance or {} setmetatable(instance, self) instance.__index = instance add(self, instance) return instance end |
To save tokens, and since I never expect to have numeric indexes in class
or any subclasses I instantiate from it, I simply add the instance to whatever object is self
when :new()
is called. ie, class[1]
is a subclass, and subclass[1] == class[1][1]
.
This works great if I use vanilla Lua ipairs()
to iterate over subclass
, but if I use Pico-8's all()
or foreach()
built-ins, things start breaking. Unlike with ipairs()
, if #subclass < #class
, the loop continues and retrieves any remaining values from class
! So, in the example below, the all()
loop will correctly access `class



EDIT: See the first reply below if you'd rather compile and use the native tool, which does seem more streamlined!
[hidden]Hi, friends!
I just put Pico-8 on my Raspberry Pi for the first time and ran into problems getting my USB gamepads to work. Unfortunately, there's no ARM build for the General Arcade SDL2 Gamepad Tool, and I didn't want to bother with compiling the native helper, so I had to take this manual route. This will only take you a couple minutes.
The final SDL string will look something like this:

First, let's get the GUID.
This issue in the GameControllerDB repo tells us a little bit about the GUID structure in SDL 2.0.5+. It varies between operating systems, and so if you copied it from a different OS to Raspbian, this might be the cause of your woes (as it was mine)!
Open a terminal and run:
$ cat /proc/bus/input/devices |
You should see your device listed in the output. We'll be concerned with the three circled values in the sysfs path, and also the version number above it. We'll come back to this output later for the name and input device path:

Convert the endianness of the three syspath IDs, and append the version. (Swap the first two characters with the last two and add four 0s). So for my gamepad:
- 0003 = 03000000
- 081f = 1f080000
- e401 = 01e40000
- 0110 = 10010000
and the end result: 030000001f08000001e4000010010000
I'm not sure if case matters here, but I went with all lowercase since I know it works.
I tried different names and SDL doesn't seem to care what you call the gamepad, but I went with the weirdo name I was provided, extra spaces and all:

Finally, let's get our mappings. Install jstest if you don't have it:
$ sudo apt update $ sudo apt install jstest |
And also refer to the Handler section in our original output to know which input device to pass to jstest.

For me, it's js0, so I'll pass /dev/input/js0 to jstest:
$ jstest --normal /dev/input/js0 |
The output looks like this, and is interactive. Each switch should flip when you push a button on the gamepad. Be sure to note the corresponding axis or button numbers.

Now that we know what button is what, we just need to add them to our config string. SDL assumes an Xbox-like gamepad layout. Together with the standard Pico-8 layout it will be mapped like this, but with the button numbers you collected from jstest:
- a: β
- b: π ΎοΈ
- x: π ΎοΈ
- y: β
- start: pause/options menu
- dpup: β¬οΈ
- dpdown: β¬οΈ
- dpleft: β¬
- dpright: β‘
Finally, put it all together! Here's what mine looks like, with funky spaces in the name and all buttons mapped: (note how the axes are expressed as -a1, +a1, -a0, +a0)
030000001f08000001e4000010010000,USB gamepad ,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,lefttrigger:b6,righttrigger:b7, |
Drop that into your sdl_controllers.txt, and it should map successfully. Fire up Pico-8 in a separate terminal window, and then check the log. You should see something like this towards the end:

If it was unsuccessful, it will look like this:

Good luck! π






Ran into this on MacOS Mojave. If you put a '.' in the filename when you export binaries, the unzipped app will launch just fine, but the zipped one won't.
I made a quick video:
https://youtu.be/NZHUZV4gLGU
Hi, friends!
I've just finished my first ever video game!
I just want to thank this entire community for existing and being so helpful and friendly. I discovered Pico-8 in April; at the peak of COVID-19 hitting my hometown, and in the depths of a massive depression brought on by isolation/lack of work/personal losses from the pandemic. It's been a lifelong dream to make a game, but I never thought I'd ever actually accomplish it, and making a little progress on this project each day feels like one of the few things that has really kept me going. So, thank you all!!!
Special thanks to @Liquidream for leading me here in the first place, and being kind enough to do some playtesting and providing lots of helpful feedback along the way. Also thanks to @MBoffin for their zine, which got me started, and for feedback in the forums when I was trying to figure out managing game state.








